#pragma once
#include "CGIPrefix.h"
#include "CGIResource.h"
#include "ExclusiveDepthStencil.h"

namespace Alice
{
    
	class FGraphicsPipelineStateInitializer
	{
	public:
		FBoundShaderStateInput			mBoundShaderStateInput;
		CGIBlendState*					mCGIBlendState;
		CGIRasterizerState*				RasterizerState;
		CGIDepthStencilState*			DepthStencilState;
		FImmutableSamplerState			ImmutableSamplerState;
		EPrimitiveType					PrimitiveType;
		uint32							RenderTargetsEnabled;
		std::vector<EPixelFormat>		RenderTargetFormats;
		std::vector<ETextureCreateFlags> RenderTargetFlags;
		EPixelFormat					DepthStencilTargetFormat;
		ETextureCreateFlags				DepthStencilTargetFlag;
		ERenderTargetLoadAction			DepthTargetLoadAction;
		ERenderTargetStoreAction		DepthTargetStoreAction;
		ERenderTargetLoadAction			StencilTargetLoadAction;
		ERenderTargetStoreAction		StencilTargetStoreAction;
		ExclusiveDepthStencil			DepthStencilAccess;
		uint16							NumSamples;
		ESubpassHint					SubpassHint;
		uint8							SubpassIndex;
		EConservativeRasterization		ConservativeRasterization;
		bool							bDepthBounds;
		uint8							MultiViewCount;
		bool							bHasFragmentDensityAttachment;
		bool							bAllowVariableRateShading;
		EVRSShadingRate					ShadingRate;
		// Note: these flags do NOT affect compilation of this PSO.
		// The resulting object is invariant with respect to whatever is set here, they are
		// behavior hints.
		// They do not participate in equality comparisons or hashing.
		union
		{
			struct
			{
				uint16					Reserved			: 11;
				uint16					bPSOPrecache		: 1;
				uint16					bFromPSOFileCache	: 1;
				uint16					PrecacheCompileType : 3;
			};
			uint16						Flags;
		};
		enum class EPSOPrecacheCompileType : uint8
		{
			NotSet = 0,
			MinPri = 1,
			NormalPri = 2,
			MaxPri = 3,

			NumTypes = 4,
		};
		static_assert((int)EPSOPrecacheCompileType::MaxPri < (1<<3) ); // ensure MaxPri fits within PrecacheCompileType
		void SetPSOPrecacheCompileType(EPSOPrecacheCompileType PrecacheCompileTypeIN) 
		{ 
			check(PrecacheCompileTypeIN <= EPSOPrecacheCompileType::MaxPri && PrecacheCompileTypeIN >= EPSOPrecacheCompileType::MinPri);
			PrecacheCompileType = (uint16)PrecacheCompileTypeIN;
		}
		EPSOPrecacheCompileType GetPSOPrecacheCompileType() const {	return (EPSOPrecacheCompileType)PrecacheCompileType; }
		// Cached hash off all state data provided at creation time (Only contains hash of data which influences the PSO precaching for the current platform)
		// Created from hashing the state data instead of the pointers which are used during fast runtime cache checking and compares
		uint64							StatePrecachePSOHash;
		FGraphicsPipelineStateInitializer()
		: mCGIBlendState(nullptr)
		, RasterizerState(nullptr)
		, DepthStencilState(nullptr)
		, RenderTargetsEnabled(0)
		, RenderTargetFormats(InPlace, EPixelFormat::PF_Unknown)
		, RenderTargetFlags(InPlace, ETextureCreateFlags::None)
		, DepthStencilTargetFormat(EPixelFormat::PF_Unknown)
		, DepthStencilTargetFlag(ETextureCreateFlags::None)
		, DepthTargetLoadAction(ERenderTargetLoadAction::ENoAction)
		, DepthTargetStoreAction(ERenderTargetStoreAction::ENoAction)
		, StencilTargetLoadAction(ERenderTargetLoadAction::ENoAction)
		, StencilTargetStoreAction(ERenderTargetStoreAction::ENoAction)
		, NumSamples(0)
		, SubpassHint(ESubpassHint::None)
		, SubpassIndex(0)
		, ConservativeRasterization(EConservativeRasterization::Disabled)
		, bDepthBounds(false)
		, MultiViewCount(0)
		, bHasFragmentDensityAttachment(false)
		, bAllowVariableRateShading(true)
		, ShadingRate(EVRSShadingRate::VRSSR_1x1)
		, Flags(0)
		, StatePrecachePSOHash(0)
		{
#if PLATFORM_WINDOWS
			static_assert(sizeof(TRenderTargetFormats::ElementType) == sizeof(uint8/*EPixelFormat*/), "Change TRenderTargetFormats's uint8 to EPixelFormat's size!");
#endif
			static_assert(PF_MAX < MAX_uint8, "TRenderTargetFormats assumes EPixelFormat can fit in a uint8!");
		}
		FGraphicsPipelineStateInitializer(
			FBoundShaderStateInput		InBoundShaderState,
			CGIBlendState*				InBlendState,
			CGIRasterizerState*		InRasterizerState,
			CGIDepthStencilState*		InDepthStencilState,
			FImmutableSamplerState		InImmutableSamplerState,
			EPrimitiveType				InPrimitiveType,
			uint32						InRenderTargetsEnabled,
			const std::vector<EPixelFormat>&	InRenderTargetFormats,
			const std::vector<ETextureCreateFlags>&	InRenderTargetFlags,
			EPixelFormat				InDepthStencilTargetFormat,
			ETextureCreateFlags			InDepthStencilTargetFlag,
			ERenderTargetLoadAction		InDepthTargetLoadAction,
			ERenderTargetStoreAction	InDepthTargetStoreAction,
			ERenderTargetLoadAction		InStencilTargetLoadAction,
			ERenderTargetStoreAction	InStencilTargetStoreAction,
			ExclusiveDepthStencil		InDepthStencilAccess,
			uint16						InNumSamples,
			ESubpassHint				InSubpassHint,
			uint8						InSubpassIndex,
			EConservativeRasterization	InConservativeRasterization,
			uint16						InFlags,
			bool						bInDepthBounds,
			uint8						InMultiViewCount,
			bool						bInHasFragmentDensityAttachment,
			bool						bInAllowVariableRateShading,
			EVRSShadingRate				InShadingRate)
			: mBoundShaderStateInput(InBoundShaderState)
			, mCGIBlendState(InBlendState)
			, RasterizerState(InRasterizerState)
			, DepthStencilState(InDepthStencilState)
			, ImmutableSamplerState(InImmutableSamplerState)
			, PrimitiveType(InPrimitiveType)
			, RenderTargetsEnabled(InRenderTargetsEnabled)
			, RenderTargetFormats(InRenderTargetFormats)
			, RenderTargetFlags(InRenderTargetFlags)
			, DepthStencilTargetFormat(InDepthStencilTargetFormat)
			, DepthStencilTargetFlag(InDepthStencilTargetFlag)
			, DepthTargetLoadAction(InDepthTargetLoadAction)
			, DepthTargetStoreAction(InDepthTargetStoreAction)
			, StencilTargetLoadAction(InStencilTargetLoadAction)
			, StencilTargetStoreAction(InStencilTargetStoreAction)
			, DepthStencilAccess(InDepthStencilAccess)
			, NumSamples(InNumSamples)
			, SubpassHint(InSubpassHint)
			, SubpassIndex(InSubpassIndex)
			, ConservativeRasterization(EConservativeRasterization::Disabled)
			, bDepthBounds(bInDepthBounds)
			, MultiViewCount(InMultiViewCount)
			, bHasFragmentDensityAttachment(bInHasFragmentDensityAttachment)
			, bAllowVariableRateShading(bInAllowVariableRateShading)
			, ShadingRate(InShadingRate)
			, Flags(InFlags)
			, StatePrecachePSOHash(0)
		{
		}
	};
}
